#ifndef __DBCOM_H__
#define __DBCOM_H__

#define CONNECT_QT	             	50
#define HANDLER_BIND_QT                 10
#define HANDLER_DEFINE_QT               30
#define LOB_BUF_LEN             	8192
#define SQL_BUF_LEN             	1024
#define CUR_BUF_ALLOC_QT		100

#define DefaultDefinition 		sb4 status, errcode

#define ThrdConn                	a_thrd_conn[thrd_index]

#define CheckErr(a) \
status=checkerr(ThrdConn.p_herr, a, &errcode)

#define ReturnErr(a) \
CheckErr(a); \
if(status==OCI_ERROR)  goto ERROR

#define StartFunc \
ReturnErr(OCIHandleAlloc((CONST dvoid *)p_henv, \
    (dvoid **)&ThrdConn.p_hstmt, OCI_HTYPE_STMT, \
    (size_t)0, (dvoid **)NULL))

#define EndFunc \
errcode=(sb4)DB_OK; \
ERROR: \
OCIHandleFree((dvoid *)ThrdConn.p_hstmt, OCI_HTYPE_STMT); \
return((int)errcode)

#define StmtPrepare \
OCIStmtPrepare(ThrdConn.p_hstmt, ThrdConn.p_herr, \
    ThrdConn.sql, (ub4)strlen((char *)ThrdConn.sql), \
    (ub4)OCI_NTV_SYNTAX, (ub4)OCI_DEFAULT)

#define StmtExecute \
OCIStmtExecute(ThrdConn.p_hsvc, ThrdConn.p_hstmt, \
    ThrdConn.p_herr, \
    (ub4)1, (ub4)0, \
    (CONST OCISnapshot *)NULL, (OCISnapshot *)NULL, \
    OCI_DEFAULT)

#define StmtOpen \
OCIStmtExecute(ThrdConn.p_hsvc, ThrdConn.p_hstmt, \
    ThrdConn.p_herr, \
    (ub4)0, (ub4)0, \
    (CONST OCISnapshot *)NULL, (OCISnapshot *)NULL, \
    OCI_DEFAULT)

#define StmtFetch \
OCIStmtFetch2(ThrdConn.p_hstmt, ThrdConn.p_herr, \
    (ub4)1, (ub2)OCI_DEFAULT, (sb4)0, (ub4)OCI_DEFAULT)

#define DefinePos(Pos,Host,Size,Type) \
OCIDefineByPos(ThrdConn.p_hstmt, &ThrdConn.a_hdef[Pos-1], \
    ThrdConn.p_herr, \
    (ub4)Pos, (dvoid *)Host, (sb4)Size, (ub2)Type, \
    (dvoid *)NULL, (ub2 *)NULL, (ub2 *)NULL, OCI_DEFAULT)

#define BindName(Order,Name,Host,Size,Type) \
OCIBindByName(ThrdConn.p_hstmt, &ThrdConn.a_hbnd[Order-1], \
    ThrdConn.p_herr, \
    (CONST text *)":"#Name, (sb4)-1, \
    (dvoid *)Host, (sb4)Size, (ub2)Type, \
    (dvoid *)NULL, (ub2 *)NULL, (ub2 *)NULL, \
    (ub4)0, (ub4 *)NULL, OCI_DEFAULT)

#define BindPos(Pos,Host,Size,Type) \
OCIBindByPos(ThrdConn.p_hstmt, &ThrdConn.a_hbnd[Pos-1], \
    ThrdConn.p_herr, \
    (ub4)Pos, (dvoid *)Host, (sb4)Size, (ub2)Type, \
    (dvoid *)NULL, (ub2 *)NULL, (ub2 *)NULL, \
    (ub4)0, (ub4 *)NULL, OCI_DEFAULT)

#define  CurBuf(Table) a_##Table

#define  CurBufLast(Table) a_##Table[Table##_real_qt]

#define  DefCurBuf(Table) \
    Table##_t Table; \
    Table##_t *a_##Table; \
    int Table##_alloc_qt, Table##_real_qt

#define InitCurBuf(Table) \
do \
{ \
    if(!(a_##Table=(Table##_t *)malloc(sizeof(Table##_t)*CUR_BUF_ALLOC_QT))) \
        goto ERROR; \
    Table##_alloc_qt=CUR_BUF_ALLOC_QT; \
    Table##_real_qt=0; \
} while(0)

#define ExpandCurBuf(Table) \
do \
{ \
    Table##_t *ptr; \
    if(Table##_real_qt<Table##_alloc_qt) \
    {    Table##_real_qt++;  break;   } \
    if(!(ptr=(Table##_t *)realloc(a_##Table, sizeof(Table##_t)*(Table##_alloc_qt+CUR_BUF_ALLOC_QT)))) \
        goto ERROR; \
    a_##Table=ptr; \
    Table##_alloc_qt+=CUR_BUF_ALLOC_QT; \
    Table##_real_qt++; \
} while(0)

#define ProcCursor(Table) \
do \
{ \
    InitCurBuf(Table); \
    while(1) \
    { \
        CheckErr(StmtFetch); \
        if(status!=OCI_SUCCESS && status!=OCI_NO_DATA) \
            goto ERROR; \
        if(status==OCI_NO_DATA)  break; \
        CurBufLast(Table)=Table; \
        ExpandCurBuf(Table); \
    } \
    *pa_##Table=CurBuf(Table); \
    *p_##Table##_qt=Table##_real_qt; \
} while(0);

#define ProcCursorRows(Table,Rows) \
do \
{ \
    DefCurBuf(Table); \
    InitCurBuf(Table); \
    while(Table##_real_qt<Rows) \
    { \
        CheckErr(StmtFetch); \
        if(status!=OCI_SUCCESS && status!=OCI_NO_DATA) \
            goto ERROR; \
        if(status==OCI_NO_DATA)  break; \
        CurBufLast(Table)=Table; \
        ExpandCurBuf(Table); \
    } \
    *pa_##Table=CurBuf(Table); \
    *p_##Table##_qt=Table##_real_qt; \
} while(0);

extern OCIEnv *p_henv;
typedef struct
{
    int connected;
    OCIError *p_herr;
    OCISvcCtx *p_hsvc;
    OCIServer *p_hsrv;
    OCISession *p_haut;
    OCIStmt *p_hstmt;
    OCIBind *a_hbnd[HANDLER_BIND_QT];
    OCIDefine *a_hdef[HANDLER_DEFINE_QT];
    OCILobLocator *p_blob;
    text sql[SQL_BUF_LEN];
} thrd_conn_t;
extern thrd_conn_t a_thrd_conn[CONNECT_QT];

extern sb4 checkerr(OCIError *p_herr, sword status, sb4 *errcode);
extern int read_blob(int thrd_index, OCILobLocator *p_blob,
    char **p_read_buf, sb4 *size, sb4 *p_errcode);
extern int write_blob(int thrd_index, char *write_buf, sb4 size,
    OCILobLocator *p_blob, sb4 *p_errcode);

#endif
